package cn.com.idmy.cloud.service;

import cn.com.idmy.base.model.Page;
import cn.com.idmy.base.util.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.NonNull;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

public interface MybatisPlusService<T, ID> {
    Logger log();

    @Nullable ID newId();

    @NotNull LambdaQueryWrapper<T> q();

    @Nullable T getNullable(@NonNull ID id);

    @Nullable T getNullable(@NotNull LambdaQueryWrapper<T> q);

    @Nullable T getNullable(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2);

    @Nullable T getNullable(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2, @NotNull SFunction<T, ?> f3);

    @NotNull T get(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2);

    @NotNull T get(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2, @NotNull SFunction<T, ?> f3);

    @NotNull T get(@NonNull ID id);

    @NotNull T get(@NotNull LambdaQueryWrapper<T> q);

    @NotNull T get(@NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params);

    <R> @Nullable R getNullable(@NotNull SFunction<T, R> f, @NonNull ID id);

    <R> @Nullable R getNullable(@NotNull SFunction<T, R> f, @NotNull LambdaQueryWrapper<T> q);

    <R> @NotNull R get(@NotNull SFunction<T, R> f, @NonNull ID id);

    <R> @NotNull R get(@NotNull SFunction<T, R> f, @NonNull ID id, @NotNull String msg, @NotNull Object... params);

    <R> @NotNull R get(@NotNull SFunction<T, R> f, @NotNull LambdaQueryWrapper<T> q);

    <R> @NotNull R get(@NotNull SFunction<T, R> f, @NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params);

    @NotNull List<T> all();

    @NotNull List<T> list(@Nullable Collection<ID> ids);

    @NotNull List<T> list(@NotNull Collection<ID> ids, @NotNull String msg, @NotNull Object... params);

    @NotNull <R> List<R> list(@NotNull SFunction<T, R> f, @Nullable Collection<ID> ids);

    @NotNull List<T> list(@NotNull LambdaQueryWrapper<T> q);

    @NotNull
    default List<T> list(@NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params) {
        return Assert.notEmpty(list(q), msg, params);
    }

    @NotNull <R> List<R> list(@NotNull SFunction<T, R> f, @NotNull LambdaQueryWrapper<T> q);

    @NotNull List<T> list(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2);

    @NotNull List<T> list(@NotNull LambdaQueryWrapper<T> q, @NotNull SFunction<T, ?> f1, @NotNull SFunction<T, ?> f2, @NotNull SFunction<T, ?> f3);

    @NotNull Map<ID, T> map(@Nullable ID[] ids);

    @NotNull Map<ID, T> map(@Nullable Collection<ID> ids);

    @NotNull <R> Map<R, T> map(@NotNull SFunction<T, R> f, @NotNull LambdaQueryWrapper<T> q);

    boolean copy(@NonNull ID id, @NotNull Consumer<T> consumer);

    @NotNull Page<T> page(@NotNull Page<?> in);

    @NotNull Page<T> page(@NotNull Page<?> in, @NotNull LambdaQueryWrapper<T> q);

    @NotNull Page<T> page(@NonNull Page<?> in, @NotNull QueryWrapper<T> q);

    boolean has(@NotNull LambdaQueryWrapper<T> q);

    void has(@NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params);

    boolean notHas(@NotNull LambdaQueryWrapper<T> q);

    void notHas(@NotNull LambdaQueryWrapper<T> q, @NotNull String msg, @NotNull Object... params);

    boolean has(@NonNull ID id);

    void has(@NonNull ID id, @NotNull String msg, @NotNull Object... params);

    boolean notHas(@NonNull ID id);

    void notHas(@NonNull ID id, @NotNull String msg, @NotNull Object... params);

    long count(@NotNull LambdaQueryWrapper<T> q);

    boolean create(@NonNull T t);

    boolean create(@NonNull Collection<T> ls);

    boolean create(@NonNull Collection<T> ls, int size);

    boolean copy(@NonNull ID id);

    boolean copy(@Nullable Collection<ID> ls);

    boolean update(@Nullable Collection<T> ls);

    boolean update(@Nullable Collection<T> ls, int size);

    boolean update(@NonNull T t);

    boolean update(@NotNull LambdaUpdateWrapper<T> u);

    default void update(@NotNull LambdaUpdateWrapper<T> u, @NotNull String msg, Object... params) {
        Assert.isTrue(update(u), msg, params);
    }

    boolean createOrUpdate(T t);

    LambdaUpdateWrapper<T> u();

    boolean delete(@NotNull LambdaQueryWrapper<T> d);

    default void delete(@NotNull LambdaQueryWrapper<T> d, @NotNull String msg, Object... params) {
        Assert.isTrue(delete(d), msg, params);
    }

    boolean delete(@NonNull ID id);

    boolean delete(@Nullable Collection<ID> ids);

    LambdaQueryWrapper<T> d();
}